/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { ArkFile, AstTreeUtils, ts } from "arkanalyzer";
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from '../BaseChecker';
import { Rule, Defects, MatcherTypes, MatcherCallback, FileMatcher, Utils } from '../../Index';
import { RuleListUtil } from "../../utils/common/DefectsList";
import { IssueReport } from "../../model/Defects";
import { RuleFix } from "../../model/Fix";

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'BraceStyleCheck');

type stringOpt = '1tbs' | 'stroustrup' | 'allman';

type Options = [
    stringOpt,
    {
        /* true（默认 false）允许块的开始和结束括号位于同一行 */
        allowSingleLine: boolean;
    }
];

interface WarnInfo {
    line: number;
    startCol: number;
    endCol: number;
    message: string;
}

type MessageInfo = {
    nextLineIsOpen: string,
    sameLineIsOpen: string,
    blockIsSameLine: string,
    nextLineIsClose: string,
    singleLineIsClose: string,
    sameLineIsClose: string
}

export class BraceStyleCheck implements BaseChecker {
    public rule: Rule;
    private defaultOptions: Options = ["1tbs", { "allowSingleLine": false }];
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    private filePath: string = '';
    // 缓存常用的 SyntaxKind 判断结果
    private readonly specialBlockKinds = new Set([
        ts.SyntaxKind.ElseKeyword,
        ts.SyntaxKind.CatchKeyword,
        ts.SyntaxKind.FinallyKeyword
    ]);

    // 使用 WeakMap 缓存节点的行号信息，避免重复计算
    private readonly lineCache = new WeakMap<ts.Node, number>();

    // 缓存已处理过的节点信息
    private readonly processedNodes = new WeakMap<ts.Node, {
        indent: string;
        isClassOrInterface: boolean;
    }>();

    public metaData: BaseMetaData = {
        severity: 1,
        ruleDocPath: 'docs/brace-style-check.md',
        description: 'Enforce consistent brace style for blocks.',
    };

    public messages: MessageInfo = {
        nextLineIsOpen: "Opening curly brace does not appear on the same line as controlling statement.",
        sameLineIsOpen: "Opening curly brace appears on the same line as controlling statement.",
        blockIsSameLine: "Statement inside of curly braces should be on next line.",
        nextLineIsClose: "Closing curly brace does not appear on the same line as the subsequent block.",
        singleLineIsClose: "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
        sameLineIsClose: "Closing curly brace appears on the same line as the subsequent block."
    }

    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const fileMatcherCb: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check,
        };

        return [fileMatcherCb];
    }

    private getDefaultOption(): Options {
        if (this.rule && this.rule.option && this.rule.option.length > 0) {
            return this.rule.option as Options;
        }
        return ["1tbs", { "allowSingleLine": false }];
    }

    public check = (target: ArkFile) => {
        try {
            this.defaultOptions = this.getDefaultOption();
            let code = target.getCode();
            if (!code) {
                return;
            }
            this.filePath = target.getFilePath();

            if (this.filePath.endsWith('.ets')) {
                //   如果是ets文件需要将'struct ' 关键字替换为 ' class '在进行检查
                code = code.replace('struct ', ' class ');
            }

            const sourceFile = AstTreeUtils.getASTNode(target.getName(), code);
            this.checkAllBlocks(sourceFile);

        } catch (error) {
            logger.error(`Error occurred while checking file: ${target.getFilePath()}, Error: ${error}`);
        }
    }

    /**
     * 通用的 AST 节点遍历函数
     * @param sourceFile 源文件
     * @param callback 遍历每个节点时执行的回调函数
     */
    private traverseAST(sourceFile: ts.SourceFile, callback: (node: ts.Node) => void) {
        const traverse = (node: ts.Node) => {
            callback(node);
            ts.forEachChild(node, traverse);
        };
        traverse(sourceFile);
    }

    // 检查所有花括号的位置
    checkAllBlocks(sourceFile: ts.SourceFile) {
        const findBraceTokens = (node: ts.Node): [ts.Node | null, ts.Node | null] => {
            let openBrace: ts.Node | null = null;
            let closeBrace: ts.Node | null = null;

            // 遍历所有子token
            const tokens = node.getChildren(sourceFile);
            for (const token of tokens) {
                if (token.kind === ts.SyntaxKind.OpenBraceToken) {
                    openBrace = token;
                }
                if (token.kind === ts.SyntaxKind.CloseBraceToken) {
                    closeBrace = token;
                }
            }

            return [openBrace, closeBrace];
        };

        this.traverseAST(sourceFile, (node) => {
            if (ts.isBlock(node) ||
                ts.isClassDeclaration(node) ||
                ts.isInterfaceDeclaration(node) ||
                ts.isEnumDeclaration(node) ||
                ts.isModuleDeclaration(node) ||
                ts.isNamespaceExportDeclaration(node) ||
                ts.isModuleBlock(node) ||
                ts.isCaseBlock(node) ||
                ts.isSwitchStatement(node)) {

                const [openBrace, closeBrace] = findBraceTokens(node);

                if (openBrace && closeBrace) {
                    try {
                        this.validateCurlyPair(node, sourceFile, openBrace, closeBrace);
                    } catch (error) {
                        console.error(`Error checking block at position ${node.getStart()}:`, error);
                    }
                }
            }
        });
    }

    // 节点类型判断
    private nodeKindIsSpecialBlock(node: ts.Node): boolean {
        return this.specialBlockKinds.has(node.kind);
    }

    // 同行判断，使用缓存
    private isTokenOnSameLine(left: ts.Node | null, right: ts.Node | null): boolean {
        if (!left || !right) return false;

        const getLineNumber = (node: ts.Node): number => {
            let line = this.lineCache.get(node);
            if (line === undefined) {
                line = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart()).line;
                this.lineCache.set(node, line);
            }
            return line;
        };

        return getLineNumber(left) === getLineNumber(right);
    }

    private validateCurlyPair(
        node: ts.Node,
        sourceFile: ts.SourceFile,
        openingCurlyToken: ts.Node | ts.Token<ts.SyntaxKind.OpenBraceToken>,
        closingCurlyToken: ts.Node | ts.Token<ts.SyntaxKind.CloseBraceToken>
    ): void {
        // 确保所有token都有效
        if (!openingCurlyToken || !closingCurlyToken) return;

        const style = this.defaultOptions[0];
        const allowSingleLine = this.defaultOptions[1].allowSingleLine;
        const isSingleLine = this.isTokenOnSameLine(openingCurlyToken, closingCurlyToken);

        // 获取左花括号前的token 
        const tokenBeforeOpeningCurly = this.findTokenBeforeOpeningCurly(openingCurlyToken, sourceFile);
        // 获取右花括号前的token 
        const tokenBeforeClosingCurly = this.findTokenBeforeClosingCurly(closingCurlyToken, sourceFile);
        // 获取左花括号后的token 
        const tokenAfterOpeningCurly = this.findTokenAfterOpeningCurly(openingCurlyToken, sourceFile);
        // 获取右花括号后的token 
        const tokenAfterClosingCurly = this.findTokenAfterClosingCurly(closingCurlyToken, sourceFile);

        // 检查是否是特殊块（else 或 catch 或 finally）
        const isSpecialBlock = tokenAfterClosingCurly && this.nodeKindIsSpecialBlock(tokenAfterClosingCurly);

        // 检查是否是完全单行的情况
        const isCompletelyOneLine = allowSingleLine &&
            ((style === '1tbs' && (!isSpecialBlock || this.isTokenOnSameLine(closingCurlyToken, tokenAfterClosingCurly))) ||
                (style === 'stroustrup' && !isSpecialBlock)) &&
            isSingleLine &&
            tokenBeforeOpeningCurly &&
            this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken);

        // 如果是允许的单行情况，跳过检查
        if (isCompletelyOneLine) {
            return;
        }

        // 检查类声明和静态块
        if (ts.isClassDeclaration(node) || ts.isClassStaticBlockDeclaration(node)) {
            this.validateClassBraces(
                node, style, allowSingleLine, isSingleLine,
                tokenBeforeOpeningCurly, tokenAfterOpeningCurly,
                tokenBeforeClosingCurly, tokenAfterClosingCurly,
                openingCurlyToken, closingCurlyToken, sourceFile
            );
            return;
        }

        // 检查左花括号位置
        this.validateOpeningBrace(
            node, style, allowSingleLine, isSingleLine,
            tokenBeforeOpeningCurly, openingCurlyToken,
            sourceFile
        );

        // 检查块内语句
        this.validateBlockStatements(
            node, style, allowSingleLine, isSingleLine,
            tokenAfterOpeningCurly, openingCurlyToken,
            isSpecialBlock, sourceFile
        );

        // 检查右花括号
        this.validateClosingBrace(
            node, style, allowSingleLine, isSingleLine,
            tokenBeforeClosingCurly, closingCurlyToken,
            tokenAfterClosingCurly, openingCurlyToken,
            isSpecialBlock, sourceFile
        );
    }

    private validateClassBraces(
        node: ts.Node,
        style: stringOpt,
        allowSingleLine: boolean,
        isSingleLine: boolean,
        tokenBeforeOpeningCurly: ts.Node | null,
        tokenAfterOpeningCurly: ts.Node | null,
        tokenBeforeClosingCurly: ts.Node | null,
        tokenAfterClosingCurly: ts.Node | null,
        openingCurlyToken: ts.Node,
        closingCurlyToken: ts.Node,
        sourceFile: ts.SourceFile
    ): void {
        // 检查是否是完全单行的类声明
        const isCompletelyOneLine = allowSingleLine &&
            isSingleLine &&
            tokenBeforeOpeningCurly &&
            this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken);

        // 如果是允许单行且确实是单行的情况，跳过检查
        if (isCompletelyOneLine) {
            return;
        }

        // 检查开始花括号位置
        if (style === 'allman') {
            if (tokenAfterOpeningCurly &&
                this.isTokenOnSameLine(tokenAfterOpeningCurly, openingCurlyToken)) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.blockIsSameLine,
                    sourceFile,
                    node
                );
            }
            if (tokenBeforeOpeningCurly &&
                this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken)) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.sameLineIsOpen,
                    sourceFile,
                    node
                );
            }
        } else {
            if (tokenAfterOpeningCurly &&
                this.isTokenOnSameLine(tokenAfterOpeningCurly, openingCurlyToken)) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.blockIsSameLine,
                    sourceFile,
                    node
                );
            }
            if (tokenBeforeOpeningCurly &&
                !this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken)) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.nextLineIsOpen,
                    sourceFile,
                    node
                );
            }
        }

        // 检查结束花括号位置
        if (!allowSingleLine || !this.isTokenOnSameLine(openingCurlyToken, closingCurlyToken)) {
            if (tokenBeforeClosingCurly &&
                this.isTokenOnSameLine(tokenBeforeClosingCurly, closingCurlyToken)) {
                this.addBraceStyleIssue(
                    closingCurlyToken,
                    this.messages.singleLineIsClose,
                    sourceFile,
                    node
                );
            }
        }
    }

    private validateOpeningBrace(
        node: ts.Node,
        style: stringOpt,
        allowSingleLine: boolean,
        isSingleLine: boolean,
        tokenBeforeOpeningCurly: ts.Node | null,
        openingCurlyToken: ts.Node,
        sourceFile: ts.SourceFile
    ): void {
        if (style === 'allman') {
            if (tokenBeforeOpeningCurly &&
                this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken) &&
                tokenBeforeOpeningCurly === openingCurlyToken) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.sameLineIsOpen,
                    sourceFile,
                    node
                );
            }
            // allman 风格：所有花括号都应该在新行，除非是允许的单行情况
            if (!allowSingleLine || !isSingleLine) {
                if (tokenBeforeOpeningCurly &&
                    this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken) &&
                    tokenBeforeOpeningCurly !== openingCurlyToken) {
                    this.addBraceStyleIssue(
                        openingCurlyToken,
                        this.messages.sameLineIsOpen,
                        sourceFile,
                        node
                    );
                }
            }
        } else {
            // 1tbs和stroustrup风格的处理
            if (!allowSingleLine || !isSingleLine) {
                // stroustrup风格的特殊情况：else、catch、finally等关键字后的左花括号应该新起一行
                const isStroustrupException = style === 'stroustrup' &&
                    tokenBeforeOpeningCurly?.kind === ts.SyntaxKind.CloseBraceToken;

                // 对于1tbs和stroustrup，左花括号应该和前一个token在同一行（除了stroustrup的特例）,如果tokenBeforeOpeningCurly是左花括号，说明一定换行了
                if (!isStroustrupException
                    && tokenBeforeOpeningCurly &&
                    (!this.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurlyToken) ||
                        tokenBeforeOpeningCurly === openingCurlyToken)) {
                    this.addBraceStyleIssue(
                        openingCurlyToken,
                        this.messages.nextLineIsOpen,
                        sourceFile,
                        node
                    );
                }
            }
        }
    }

    private validateBlockStatements(
        node: ts.Node,
        style: stringOpt,
        allowSingleLine: boolean,
        isSingleLine: boolean,
        tokenAfterOpeningCurly: ts.Node | null,
        openingCurlyToken: ts.Node,
        isSpecialBlock: boolean | null,
        sourceFile: ts.SourceFile
    ): void {
        // allman 风格需要特殊处理
        if (style === 'allman') {
            if (!allowSingleLine || !isSingleLine) {
                if (tokenAfterOpeningCurly &&
                    this.isTokenOnSameLine(tokenAfterOpeningCurly, openingCurlyToken)) {
                    this.addBraceStyleIssue(
                        openingCurlyToken,
                        this.messages.blockIsSameLine,
                        sourceFile,
                        node
                    );
                }
            }
        } else if (style === '1tbs') {
            // 1tbs 风格：在不允许单行或是特殊块时检查
            if (!allowSingleLine) {
                if (tokenAfterOpeningCurly &&
                    this.isTokenOnSameLine(tokenAfterOpeningCurly, openingCurlyToken)) {
                    this.addBraceStyleIssue(
                        openingCurlyToken,
                        this.messages.blockIsSameLine,
                        sourceFile,
                        node
                    );
                }
            }
        } else if (style === 'stroustrup' && !allowSingleLine) {
            // stroustrup 风格且不允许单行时，检查块内语句位置
            if (tokenAfterOpeningCurly &&
                this.isTokenOnSameLine(tokenAfterOpeningCurly, openingCurlyToken)) {
                this.addBraceStyleIssue(
                    openingCurlyToken,
                    this.messages.blockIsSameLine,
                    sourceFile,
                    node
                );
            }
        }
    }

    // 检查右花括号
    private validateClosingBrace(
        node: ts.Node,
        style: stringOpt,
        allowSingleLine: boolean,
        isSingleLine: boolean,
        tokenBeforeClosingCurly: ts.Node | null,
        closingCurlyToken: ts.Node,
        tokenAfterClosingCurly: ts.Node | null,
        openingCurlyToken: ts.Node,
        isSpecialBlock: boolean | null,
        sourceFile: ts.SourceFile
    ): void {

        if (tokenBeforeClosingCurly &&
            tokenBeforeClosingCurly !== openingCurlyToken) {
            // 检查是否是allman风格且允许单行
            const isAllmanWithSingleLine = allowSingleLine &&
                this.isTokenOnSameLine(openingCurlyToken, closingCurlyToken);

            // 只有在非allman和非stroustrup 且 单行允许的情况下才检查
            if (!isAllmanWithSingleLine &&
                this.isTokenOnSameLine(tokenBeforeClosingCurly, closingCurlyToken)) {
                this.addBraceStyleIssue(
                    closingCurlyToken,
                    this.messages.singleLineIsClose,
                    sourceFile,
                    node
                );
            }
        }

        // 检查右花括号与后续块的关系
        if (!allowSingleLine || !isSingleLine || isSpecialBlock) {
            if (tokenAfterClosingCurly) {
                if (style === 'allman' && isSpecialBlock) {
                    if (this.isTokenOnSameLine(closingCurlyToken, tokenAfterClosingCurly)) {
                        this.addBraceStyleIssue(
                            closingCurlyToken,
                            this.messages.sameLineIsClose,
                            sourceFile,
                            node
                        );
                    }
                } else if (style === '1tbs') {
                    // 1tbs 风格下，catch/else 等特殊块应该和前面的右花括号在同一行
                    const shouldBeOnSameLine = isSpecialBlock;
                    if (shouldBeOnSameLine !== this.isTokenOnSameLine(closingCurlyToken, tokenAfterClosingCurly)) {
                        this.addBraceStyleIssue(
                            closingCurlyToken,
                            shouldBeOnSameLine ? this.messages.nextLineIsClose : this.messages.sameLineIsClose,
                            sourceFile,
                            node
                        );
                    }
                } else if (style === 'stroustrup') {
                    // stroustrup 风格下，所有右花括号都应该单独一行
                    if (this.isTokenOnSameLine(closingCurlyToken, tokenAfterClosingCurly)) {
                        this.addBraceStyleIssue(
                            closingCurlyToken,
                            this.messages.sameLineIsClose,
                            sourceFile,
                            node
                        );
                    }
                }
            }
        }

    }

    /**
     * 获取左花括号前的token
     */
    private findTokenBeforeOpeningCurly(openingCurly: ts.Node, sourceFile: ts.SourceFile): ts.Node | null {
        // 获取父节点的所有子节点
        const siblings = openingCurly.parent.getChildren(sourceFile);

        // 找到左花括号的位置
        let curlyIndex = siblings.findIndex(node => node === openingCurly);

        if (!curlyIndex) {
            // 获取父节点的父节点的所有子节点
            const parentSiblings = openingCurly.parent.parent?.getChildren(sourceFile);
            if (parentSiblings) {
                // 在父层级中查找包含左花括号的节点
                curlyIndex = parentSiblings.findIndex(node =>
                    node.getChildren(sourceFile).some(child => child === openingCurly)
                );
                if (curlyIndex > 0) {
                    return parentSiblings[curlyIndex - 1];
                }
            }
            return openingCurly;
        }

        // 返回左花括号前的节点
        return siblings[curlyIndex - 1];
    }

    /**
     * 获取右花括号前的token
     */
    private findTokenBeforeClosingCurly(closingCurly: ts.Node, sourceFile: ts.SourceFile): ts.Node | null {
        let prevToken: ts.Node | null = null;
        this.traverseAST(sourceFile, (node) => {
            if (node === closingCurly) {
                return;
            }
            const lastToken = node.getLastToken(sourceFile);
            if (lastToken && lastToken.end < closingCurly.getStart()) {
                prevToken = lastToken;
            }
        });
        return prevToken;
    }

    /**
     * 获取左花括号后的token
     */
    private findTokenAfterOpeningCurly(openingCurly: ts.Node, sourceFile: ts.SourceFile): ts.Node | null {
        // 获取父节点的所有子节点
        const siblings = openingCurly.parent.getChildren(sourceFile);

        // 找到左花括号的位置
        const curlyIndex = siblings.findIndex(node => node === openingCurly);

        // 如果找到左花括号且不是最后一个节点
        if (curlyIndex !== -1 && curlyIndex < siblings.length - 1) {
            // 获取下一个节点的第一个有效token
            const nextNode = siblings[curlyIndex + 1];
            return nextNode?.getFirstToken(sourceFile) || null;
        }

        return null;
    }

    /**
     * 获取右花括号后的token
     */
    private findTokenAfterClosingCurly(closingCurly: ts.Node, sourceFile: ts.SourceFile): ts.Node | null {
        // 获取父级if语句
        const getParentIfStatement = (node: ts.Node): ts.IfStatement | null => {
            let current = node.parent;
            while (current) {
                if (ts.isIfStatement(current)) {
                    return current;
                }
                current = current.parent;
            }
            return null;
        };

        // 获取父级try语句
        const getParentTryStatement = (node: ts.Node): ts.TryStatement | null => {
            let current = node.parent;
            while (current) {
                if (ts.isTryStatement(current)) {
                    return current;
                }
                current = current.parent;
            }
            return null;
        };

        // 处理if语句相关的后续节点
        const handleIfStatement = (ifStmt: ts.IfStatement): ts.Node | null => {
            // 如果当前块是if的then块
            if (ifStmt.thenStatement && closingCurly.parent === ifStmt.thenStatement) {
                // 检查是否有else或else if
                if (ifStmt.elseStatement) {
                    // 查找else关键字
                    const elseToken = ifStmt.getChildren(sourceFile).find(child =>
                        child.kind === ts.SyntaxKind.ElseKeyword);
                    return elseToken || null;
                }
            }
            // 如果当前块是else if的then块
            else if (ifStmt.elseStatement && ts.isIfStatement(ifStmt.elseStatement) &&
                closingCurly.parent === ifStmt.elseStatement.thenStatement) {
                // 检查后续是否还有else或else if
                if (ifStmt.elseStatement.elseStatement) {
                    const elseToken = ifStmt.elseStatement.getChildren(sourceFile).find(child =>
                        child.kind === ts.SyntaxKind.ElseKeyword);
                    return elseToken || null;
                }
            }
            return null;
        };

        // 处理try语句相关的后续节点
        const handleTryStatement = (tryStmt: ts.TryStatement): ts.Node | null => {
            // 如果当前块是try块
            if (closingCurly.parent === tryStmt.tryBlock) {
                if (tryStmt.catchClause) {
                    const token = tryStmt.catchClause.getFirstToken(sourceFile);
                    return token || null;
                } else if (tryStmt.finallyBlock) {
                    const finallyToken = tryStmt.getChildren(sourceFile).find(child =>
                        child.kind === ts.SyntaxKind.FinallyKeyword);
                    return finallyToken || null;
                }
            }
            // 如果当前块是catch块
            else if (tryStmt.catchClause && closingCurly.parent === tryStmt.catchClause.block) {
                if (tryStmt.finallyBlock) {
                    const finallyToken = tryStmt.getChildren(sourceFile).find(child =>
                        child.kind === ts.SyntaxKind.FinallyKeyword);
                    return finallyToken || null;
                }
            }
            return null;
        };

        // 主要处理逻辑
        const parentIfStmt = getParentIfStatement(closingCurly);
        if (parentIfStmt) {
            const nextNode = handleIfStatement(parentIfStmt);
            if (nextNode) return nextNode;
        }

        const parentTryStmt = getParentTryStatement(closingCurly);
        if (parentTryStmt) {
            const nextNode = handleTryStatement(parentTryStmt);
            if (nextNode) return nextNode;
        }

        // 如果不是特殊情况，则按照普通方式处理
        const siblings = closingCurly.parent.getChildren(sourceFile);
        const curlyIndex = siblings.findIndex(node => node === closingCurly);
        if (curlyIndex < siblings.length - 1) {
            return siblings[curlyIndex + 1];
        }

        return null;
    }

    /**
     * 获取父节点的缩进
     * @param node 当前节点
     * @returns 父节点的缩进字符串
     */
    private getParentIndent(node: ts.Node, sourceFile: ts.SourceFile): string {
        const cached = this.processedNodes.get(node);
        if (cached) {
            return cached.indent;
        }

        const parent = node.parent;
        if (!parent) return '';

        const lineStart = sourceFile.getPositionOfLineAndCharacter(
            sourceFile.getLineAndCharacterOfPosition(parent.getStart()).line,
            0
        );
        const lineText = sourceFile.text.substring(lineStart, parent.getStart());
        const indent = lineText.match(/^\s*/)?.[0] || '';

        const isClassOrInterface = ts.isClassDeclaration(parent) ||
            ts.isInterfaceDeclaration(parent);

        this.processedNodes.set(node, {
            indent,
            isClassOrInterface
        });

        return indent;
    }

    private ruleFix(pos: number, end: number, message: string, sourceFile: ts.SourceFile, tokenNode: ts.Node, afterToken: ts.Node | null): RuleFix {
        const braceStyle = this.defaultOptions[0];
        // 获取缓存的节点信息
        const nodeInfo = this.processedNodes.get(tokenNode) || {
            indent: this.getParentIndent(tokenNode, sourceFile),
            isClassOrInterface: ts.isClassDeclaration(tokenNode.parent) || ts.isInterfaceDeclaration(tokenNode.parent)
        };

        // 获取基础缩进
        const baseIndent = nodeInfo.indent;
        // 如果是类声明的左花括号，使用父节点的缩进
        const currentIndent = nodeInfo.isClassOrInterface ? baseIndent : baseIndent + '  ';

        // 对于类声明等特殊情况，需要特殊处理缩进
        const isClassOrInterface = ts.isClassDeclaration(tokenNode.parent) ||
            ts.isInterfaceDeclaration(tokenNode.parent);

        switch (message) {
            case this.messages.nextLineIsOpen:
                switch (braceStyle) {
                    case '1tbs':
                    case 'stroustrup':
                        // 左花括号应该和控制语句在同一行
                        // 需要删除从上一行末尾到当前花括号位置的所有内容（包括换行和空白）
                        const prevTokenEnd = sourceFile.text.lastIndexOf('\n', pos);
                        return {
                            range: [prevTokenEnd, end],
                            text: ' {'
                        };
                    case 'allman':
                        // 对于类声明，保持与类名对齐
                        if (isClassOrInterface) {
                            return {
                                range: [pos, end],
                                text: baseIndent + '{'
                            };
                        }
                        // 其他情况增加缩进
                        return {
                            range: [pos, end],
                            text: currentIndent + '{'
                        };
                }
            case this.messages.nextLineIsClose:
                switch (braceStyle) {
                    case '1tbs':
                        // 处理右花括号和else/catch/finally在同一行的情况
                        if (afterToken && this.nodeKindIsSpecialBlock(afterToken)) {
                            return {
                                range: [end, afterToken.getStart()],
                                text: ' '
                            };
                        }
                        break;
                    case 'stroustrup':
                    case 'allman':
                        // 确保右花括号在新行，并保持正确缩进
                        return {
                            range: [pos, end],
                            text: '\n' + baseIndent + '}'
                        };
                }
                return { range: [-1, -1], text: '' };

            case this.messages.sameLineIsOpen:
                switch (braceStyle) {
                    case '1tbs':
                    case 'stroustrup':
                        // 保持在同一行
                        return {
                            range: [pos, end],
                            text: ' {'
                        };
                    case 'allman':
                        return {
                            range: [end, end],
                            text: '\n'
                        };
                }

            case this.messages.singleLineIsClose:
                // 处理块内容与右花括号在同一行的情况
                if (braceStyle === 'stroustrup' && afterToken) {
                    if (this.nodeKindIsSpecialBlock(afterToken)) {
                        return {
                            range: [pos, pos],
                            text: '\n' + (isClassOrInterface ? baseIndent : currentIndent)
                        };
                    }
                }
                return {
                    range: [pos, end],
                    text: '\n' + baseIndent + '}'
                };

            case this.messages.sameLineIsClose:
                // 处理右花括号与后续语句在同一行的情况
                if (braceStyle === 'stroustrup' && afterToken) {
                    if (this.nodeKindIsSpecialBlock(afterToken)) {
                        return {
                            range: [end, end],
                            text: '\n' + (isClassOrInterface ? baseIndent : currentIndent)
                        };
                    }
                }
                return {
                    range: [pos, end],
                    text: (isClassOrInterface ? baseIndent : currentIndent) + '}\n' + currentIndent
                };

            case this.messages.blockIsSameLine:
                // 处理左花括号与语句在同一行的情况
                if (braceStyle === 'allman') {
                    return {
                        range: [pos, pos],
                        text: '\n'
                    };
                }
                return {
                    range: [pos, end],
                    text: '\n' + baseIndent + '{\n' + currentIndent
                };

            default:
                return { range: [-1, -1], text: '' };
        }
    }

    private addBraceStyleIssue(
        tokenNode: ts.Node,
        message: string,
        sourceFile: ts.SourceFile,
        afterToken: ts.Node | null,
    ): void {
        const position = sourceFile.getLineAndCharacterOfPosition(tokenNode.getStart());
        const startCol = position.character + 1;
        let defect = this.addIssueReport({
            line: position.line + 1,
            startCol: startCol,
            endCol: startCol,
            message,
        });

        let pos = tokenNode.getStart();
        let end = tokenNode.getEnd();
        let fix: RuleFix = this.ruleFix(pos, end, message, sourceFile, tokenNode, afterToken);
        this.issues.push({ defect, fix });
        RuleListUtil.push(defect);
    }

    private addIssueReport(warnInfo: WarnInfo): Defects {
        this.metaData.description = warnInfo.message;
        const severity = this.rule.alert ?? this.metaData.severity;
        // 创建缺陷报告
        let defect = new Defects(warnInfo.line, warnInfo.startCol, warnInfo.endCol, this.metaData.description, severity, this.rule.ruleId,
            this.filePath, this.metaData.ruleDocPath, true, false, false);
        return defect;
    }
}
